/*
 *  Copyright 2011 yura.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */

package org.opu.vcforms.editor;

import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.undo.UndoManager;
import org.opu.vcforms.view.component.GUIProperties;

/**
 * 
 * @author yura
 */
public class TextViewImpl extends JTextArea implements TextView {

    private static final long serialVersionUID = 1906092231093452949L;
    
    private boolean saved = true; // if data geted from somewhere it`s saved.
    private File file;

    private UndoManager undoManager;
    private PropertyChangeListener changeListener;

    public TextViewImpl(PropertyChangeListener changeListener, String text, File file) {
        super(text);
        this.changeListener = changeListener;
        this.undoManager = new UndoManager();
        this.file = file;

        getDocument().addUndoableEditListener(this.undoManager);
        getDocument().addDocumentListener(new DocumentListener() {

            @Override
            public void removeUpdate(DocumentEvent e) {
                propertyChange(new PropertyChangeEvent(TextViewImpl.this, EDIT, false, true));
            }

            @Override
            public void insertUpdate(DocumentEvent e) {
                propertyChange(new PropertyChangeEvent(TextViewImpl.this, EDIT, false, true));
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                // Plain text components do not fire these events
            }
        });

        ActionMap am = getActionMap();
        am.put("Undo", new AbstractAction("Undo") {

            @Override
            public void actionPerformed(ActionEvent evt) {
                undo();
            }
        });
        am.put("Redo", new AbstractAction("Redo") {

            @Override
            public void actionPerformed(ActionEvent evt) {
                redo();
            }
        });

        getInputMap().put(KeyStroke.getKeyStroke("control Z"), "Undo");
        getInputMap().put(KeyStroke.getKeyStroke("control shift Z"), "Redo");
        getInputMap().put(KeyStroke.getKeyStroke("control Y"), "Redo");

        setFont(GUIProperties.instance().editor.getFont());
    }

    @Override
    public boolean isSaved() {
        return saved;
    }

    @Override
    public void setSaved(boolean saved) {
        boolean old = this.saved;
        this.saved = saved;
        propertyChange(new PropertyChangeEvent(TextViewImpl.this, SAVE, old, this.saved));
    }

    @Override
    public boolean undo() {
        try {
            boolean beforeUndo = undoManager.canUndo();
            undoManager.undo();
            boolean afterUndo = undoManager.canUndo();

            propertyChange(new PropertyChangeEvent(TextViewImpl.this, UNDO, beforeUndo, afterUndo));

            return afterUndo;
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    public boolean redo() {
        try {
            boolean beforeRedo = undoManager.canRedo();
            undoManager.redo();
            boolean afterRedo = undoManager.canRedo();

            propertyChange(new PropertyChangeEvent(TextViewImpl.this, REDO, beforeRedo, afterRedo));

            return afterRedo;
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if (evt.getSource() == this && SAVE.equals(evt.getPropertyName())) {
            saved = (Boolean) (evt.getNewValue() != null ? evt.getNewValue() : false);
        } else {
            saved = false;
        }
        if (changeListener != null) {
            changeListener.propertyChange(evt);
        }
    }

    @Override
    public void setChangeListener(PropertyChangeListener changeListener) {
        this.changeListener = changeListener;
    }

    public PropertyChangeListener getChangeListener() {
        return changeListener;
    }

    @Override
    public boolean canUndo() {
        return undoManager.canUndo();
    }

    @Override
    public boolean canRedo() {
        return undoManager.canRedo();
    }

    @Override
    public File getFile() {
        return file;
    }


}
